package com.kexilo.logging.service;

import com.kexilo.logging.domain.LogRecord;
import com.kexilo.logging.properties.LoggingProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 日志服务默认实现
 * 支持数据库、文件、异步等多种记录方式
 * 
 * @author Kexilo
 */
public class LoggingServiceImpl implements LoggingService {
    
    private static final Logger log = LoggerFactory.getLogger(LoggingServiceImpl.class);
    
    private final LoggingProperties properties;
    private final JdbcTemplate jdbcTemplate;
    
    public LoggingServiceImpl(LoggingProperties properties, JdbcTemplate jdbcTemplate) {
        this.properties = properties;
        this.jdbcTemplate = jdbcTemplate;
        log.info("日志服务初始化完成，模式: {}, 数据库: {}", 
                properties.getMode(), properties.getDatabase().isEnabled());
    }
    
    @Override
    public void log(LogRecord logRecord) {
        if (!properties.isEnabled()) {
            return;
        }
        
        try {
            switch (properties.getMode()) {
                case SYNC:
                    recordLog(logRecord);
                    break;
                case ASYNC:
                    logAsync(logRecord);
                    break;
                case BATCH:
                    // 批处理模式可以先缓存，定时批量处理
                    recordLog(logRecord);
                    break;
                default:
                    recordLog(logRecord);
            }
        } catch (Exception e) {
            log.error("记录日志失败: {}", logRecord.getTitle(), e);
        }
    }
    
    @Override
    @Async("loggingTaskExecutor")
    public CompletableFuture<Void> logAsync(LogRecord logRecord) {
        try {
            recordLog(logRecord);
            return CompletableFuture.completedFuture(null);
        } catch (Exception e) {
            log.error("异步记录日志失败: {}", logRecord.getTitle(), e);
            return CompletableFuture.failedFuture(e);
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void logBatch(List<LogRecord> logRecords) {
        if (!properties.isEnabled() || logRecords.isEmpty()) {
            return;
        }
        
        try {
            for (LogRecord logRecord : logRecords) {
                recordLog(logRecord);
            }
            log.debug("批量记录日志成功，数量: {}", logRecords.size());
        } catch (Exception e) {
            log.error("批量记录日志失败，数量: {}", logRecords.size(), e);
            throw e;
        }
    }
    
    @Override
    public void logLogin(String username, boolean success, String ip, String userAgent, String message) {
        LogRecord logRecord = LogRecord.builder()
                .type(LogRecord.LogType.LOGIN)
                .level(success ? LogRecord.LogLevel.INFO : LogRecord.LogLevel.WARN)
                .title(success ? "用户登录" : "用户登录失败")
                .username(username)
                .ip(ip)
                .userAgent(userAgent)
                .status(success ? 200 : 401)
                .errorMsg(success ? null : message)
                .operTime(LocalDateTime.now())
                .build();
                
        log(logRecord);
    }
    
    @Override
    public void logSecurity(String operation, String username, String ip, String details) {
        LogRecord logRecord = LogRecord.builder()
                .type(LogRecord.LogType.SECURITY)
                .level(LogRecord.LogLevel.WARN)
                .title("安全操作: " + operation)
                .username(username)
                .ip(ip)
                .params(details)
                .operTime(LocalDateTime.now())
                .build();
                
        log(logRecord);
    }
    
    @Override
    public boolean isAvailable() {
        try {
            // 检查数据库连接是否可用
            if (properties.getDatabase().isEnabled() && jdbcTemplate != null) {
                jdbcTemplate.queryForObject("SELECT 1", Integer.class);
                return true;
            }
            // 如果只启用文件记录，也认为可用
            return properties.getFile().isEnabled();
        } catch (Exception e) {
            log.warn("日志服务不可用: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 实际记录日志的私有方法
     */
    private void recordLog(LogRecord logRecord) {
        // 数据库记录
        if (properties.getDatabase().isEnabled() && jdbcTemplate != null) {
            recordToDatabase(logRecord);
        }
        
        // 文件记录
        if (properties.getFile().isEnabled()) {
            recordToFile(logRecord);
        }
        
        // 如果都没启用，至少记录到普通日志
        if (!properties.getDatabase().isEnabled() && !properties.getFile().isEnabled()) {
            log.info("操作日志: {} - {} - {} - {}", 
                    logRecord.getTitle(), logRecord.getUsername(), 
                    logRecord.getIp(), logRecord.getMethod());
        }
    }
    
    /**
     * 记录到数据库
     */
    private void recordToDatabase(LogRecord logRecord) {
        try {
            String sql = buildInsertSql();
            int result = jdbcTemplate.update(sql,
                    logRecord.getTitle(),
                    logRecord.getType() != null ? logRecord.getType().name() : null,
                    logRecord.getLevel() != null ? logRecord.getLevel().name() : null,
                    logRecord.getMethod(),
                    logRecord.getUrl(),
                    logRecord.getClassName(),
                    logRecord.getMethodName(),
                    logRecord.getUsername(),
                    logRecord.getDeptName(),
                    logRecord.getIp(),
                    logRecord.getOperLocation(),
                    logRecord.getParams(),
                    logRecord.getResult(),
                    logRecord.getStatus(),
                    logRecord.getErrorMsg(),
                    logRecord.getCostTime(),
                    logRecord.getOperTime(),
                    logRecord.getTenantId(),
                    logRecord.getUserAgent(),
                    logRecord.getBrowser(),
                    logRecord.getOs(),
                    logRecord.getTraceId()
            );
            
            if (result > 0) {
                log.debug("数据库记录日志成功: {}", logRecord.getTitle());
            }
        } catch (Exception e) {
            log.error("数据库记录日志失败: {}", logRecord.getTitle(), e);
            // 不抛出异常，避免影响业务流程
        }
    }
    
    /**
     * 记录到文件
     */
    private void recordToFile(LogRecord logRecord) {
        try {
            // 这里可以实现文件记录逻辑
            // 为了简化，暂时记录到普通日志
            log.info("文件日志: {} - {} - {} - {} - {}", 
                    logRecord.getOperTime(),
                    logRecord.getTitle(), 
                    logRecord.getUsername(), 
                    logRecord.getIp(), 
                    logRecord.getStatus());
        } catch (Exception e) {
            log.error("文件记录日志失败: {}", logRecord.getTitle(), e);
        }
    }
    
    /**
     * 构建插入SQL
     */
    private String buildInsertSql() {
        String tableName = properties.getDatabase().getTableName();
        return "INSERT INTO " + tableName + " (" +
                "title, log_type, log_level, method, url, class_name, method_name, " +
                "username, dept_name, oper_ip, oper_location, oper_param, json_result, " +
                "status, error_msg, cost_time, oper_time, tenant_id, user_agent, browser, os, trace_id" +
                ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
    }
}
